En omfattende guide til Cross-Origin Resource Sharing (CORS), der dækker konfiguration, sikkerhedsmæssige konsekvenser og bedste praksis for udviklere.
Cross-Origin Resource Sharing (CORS): Konfiguration og bedste praksis for sikkerhed
I webudviklingens verden er sikkerhed altafgørende. Et kritisk aspekt af websikkerhed er at styre, hvordan websider fra én oprindelse kan få adgang til ressourcer fra en anden oprindelse. Det er her, Cross-Origin Resource Sharing (CORS) kommer ind i billedet. CORS er en sikkerhedsfunktion i browseren, der begrænser websider i at foretage anmodninger til et andet domæne end det, der leverede websiden. Denne mekanisme er på plads for at forhindre ondsindede websteder i at få adgang til følsomme data. Denne artikel giver en omfattende guide til CORS, der dækker konfiguration, sikkerhedsmæssige konsekvenser og bedste praksis.
Forståelse af Same-Origin Policy
CORS er bygget på fundamentet af Same-Origin Policy, en fundamental sikkerhedsmekanisme implementeret af webbrowsere. Same-origin policy begrænser websider i at foretage anmodninger til et andet domæne end det, der leverede websiden. To URL'er anses for at have samme oprindelse, hvis de har samme protokol (f.eks. HTTP eller HTTPS), host (f.eks. example.com) og port (f.eks. 80 eller 443). For eksempel:
http://example.comoghttp://example.com/pathhar samme oprindelse.http://example.comoghttps://example.comer forskellige oprindelser (forskellige protokoller).http://example.comoghttp://www.example.comer forskellige oprindelser (forskellige hosts).http://example.com:80oghttp://example.com:8080er forskellige oprindelser (forskellige porte).
Same-origin policy er designet til at forhindre Cross-Site Scripting (XSS)-angreb, hvor et ondsindet websted injicerer scripts i et betroet websted for at stjæle brugerdata eller udføre uautoriserede handlinger. Uden same-origin policy kunne et ondsindet websted potentielt få adgang til dine bankkontooplysninger, hvis du var logget ind på din netbank i en anden fane.
Hvad er Cross-Origin Resource Sharing (CORS)?
Selvom same-origin policy er afgørende for sikkerheden, kan den også være restriktiv i legitime scenarier, hvor websteder har brug for at få adgang til ressourcer fra forskellige oprindelser. For eksempel kan en webapplikation, der er hostet på example.com, have brug for at hente data fra en API, der er hostet på api.example.net. CORS giver en mekanisme til at omgå same-origin policy på en kontrolleret måde, hvilket tillader websider at foretage anmodninger på tværs af oprindelser, når det er eksplicit godkendt af serveren.
CORS fungerer ved at tilføje HTTP-headere til svaret fra serveren, som angiver, hvilke oprindelser der har tilladelse til at få adgang til ressourcen. Browseren kontrollerer derefter disse headere og blokerer anmodningen, hvis oprindelsen af den webside, der foretager anmodningen, ikke er tilladt.
Sådan fungerer CORS: HTTP-headerne
CORS er afhængig af specifikke HTTP-headere for at facilitere anmodninger på tværs af oprindelser. Her er de vigtigste involverede headere:
1. Origin (Anmodnings-header)
Origin-headeren sendes af browseren i anmodninger på tværs af oprindelser. Den angiver oprindelsen (protokol, host og port) for den webside, der foretager anmodningen. For eksempel:
Origin: http://example.com
2. Access-Control-Allow-Origin (Svar-header)
Access-Control-Allow-Origin-headeren er den vigtigste header i CORS. Den specificerer, hvilke oprindelser der har tilladelse til at tilgå ressourcen. Den kan have en af følgende værdier:
- En specifik oprindelse: For eksempel tillader
Access-Control-Allow-Origin: http://example.comkun anmodninger frahttp://example.com. *(wildcard):Access-Control-Allow-Origin: *tillader anmodninger fra enhver oprindelse. Dette bør bruges med forsigtighed, da det reelt deaktiverer same-origin policy for den pågældende ressource.
Eksempel:
Access-Control-Allow-Origin: https://www.example.com
3. Access-Control-Allow-Methods (Svar-header)
Access-Control-Allow-Methods-headeren specificerer de HTTP-metoder (f.eks. GET, POST, PUT, DELETE), der er tilladt i anmodningen på tværs af oprindelser. Dette er påkrævet for preflight-anmodninger (forklaret nedenfor).
Eksempel:
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
4. Access-Control-Allow-Headers (Svar-header)
Access-Control-Allow-Headers-headeren specificerer de HTTP-headere, der er tilladt i anmodningen på tværs af oprindelser. Dette er også påkrævet for preflight-anmodninger.
Eksempel:
Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With
5. Access-Control-Allow-Credentials (Svar-header)
Access-Control-Allow-Credentials-headeren specificerer, om browseren skal inkludere legitimationsoplysninger (f.eks. cookies, authorization-headere) i anmodningen på tværs af oprindelser. Den kan have en af to værdier: true eller false. Hvis true er sat, kan Access-Control-Allow-Origin-headeren ikke sættes til *. Den skal være en specifik oprindelse.
Eksempel:
Access-Control-Allow-Credentials: true
6. Access-Control-Max-Age (Svar-header)
Access-Control-Max-Age-headeren specificerer det antal sekunder, browseren kan cache resultaterne af preflight-anmodningen. Dette kan forbedre ydeevnen ved at reducere antallet af preflight-anmodninger.
Eksempel:
Access-Control-Max-Age: 3600
Simple anmodninger vs. preflight-anmodninger
CORS skelner mellem to typer af anmodninger på tværs af oprindelser: simple anmodninger og preflight-anmodninger.
Simple anmodninger
En simpel anmodning er en anmodning, der opfylder følgende kriterier:
- Metoden er
GET,HEADellerPOST. - Hvis metoden er
POST, erContent-Type-headeren en af følgende:application/x-www-form-urlencoded,multipart/form-dataellertext/plain. - Anmodningen sætter ingen brugerdefinerede headere (udover dem, der automatisk sættes af browseren).
For simple anmodninger sender browseren anmodningen direkte til serveren. Serveren svarer derefter med de relevante CORS-headere. Hvis oprindelsen er tilladt, behandler browseren svaret. Ellers blokerer browseren svaret og kaster en fejl.
Preflight-anmodninger
En preflight-anmodning sendes af browseren, før den faktiske anmodning på tværs af oprindelser foretages, hvis anmodningen ikke opfylder kriterierne for en simpel anmodning. Dette sker typisk, når anmodningen bruger en anden metode end GET, HEAD eller POST, eller når anmodningen sætter brugerdefinerede headere.
Preflight-anmodningen er en OPTIONS-anmodning, der inkluderer følgende headere:
Origin: Oprindelsen af den webside, der foretager anmodningen.Access-Control-Request-Method: Den HTTP-metode, der vil blive brugt i den faktiske anmodning.Access-Control-Request-Headers: En komma-separeret liste over de brugerdefinerede headere, der vil blive brugt i den faktiske anmodning.
Serveren svarer derefter med følgende headere:
Access-Control-Allow-Origin: Den oprindelse, der har tilladelse til at tilgå ressourcen.Access-Control-Allow-Methods: De HTTP-metoder, der er tilladt i anmodningen på tværs af oprindelser.Access-Control-Allow-Headers: De HTTP-headere, der er tilladt i anmodningen på tværs af oprindelser.Access-Control-Max-Age: Det antal sekunder, browseren kan cache resultaterne af preflight-anmodningen.
Hvis serveren svarer med de relevante CORS-headere, fortsætter browseren med den faktiske anmodning på tværs af oprindelser. Ellers blokerer browseren anmodningen og kaster en fejl.
Eksempler på CORS-konfiguration
Implementeringen af CORS varierer afhængigt af den server-side teknologi, du bruger. Her er nogle eksempler for almindelige server-side sprog og frameworks:
Node.js med Express
Brug af cors-middleware er en almindelig tilgang til at konfigurere CORS i Node.js med Express:
const express = require('express');
const cors = require('cors');
const app = express();
// Enable CORS for all origins
app.use(cors());
// Enable CORS for a specific origin
// app.use(cors({ origin: 'http://example.com' }));
// Enable CORS with options
// app.use(cors({
// origin: ['http://example.com', 'http://localhost:3000'],
// methods: ['GET', 'POST', 'PUT', 'DELETE'],
// allowedHeaders: ['Content-Type', 'Authorization'],
// credentials: true
// }));
app.get('/api/data', (req, res) => {
res.json({ message: 'Hello from the API!' });
});
app.listen(3001, () => {
console.log('Server listening on port 3001');
});
Python med Flask
Du kan bruge Flask-CORS-udvidelsen til at konfigurere CORS i Flask:
from flask import Flask
from flask_cors import CORS
app = Flask(__name__)
# Enable CORS for all origins
CORS(app)
# Enable CORS for specific origins
# CORS(app, origins=['http://example.com', 'http://localhost:3000'])
@app.route('/api/data')
def get_data():
return {'message': 'Hello from the API!'}
if __name__ == '__main__':
app.run(port=3001)
Java med Spring Boot
Spring Boot giver flere måder at konfigurere CORS på. En tilgang er at bruge @CrossOrigin-annotationen:
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@CrossOrigin(origins = "http://example.com") // Specific origin
public class ApiController {
@GetMapping("/api/data")
public String getData() {
return "Hello from the API!";
}
}
// Global CORS configuration (using WebMvcConfigurer):
// @Configuration
// public class CorsConfig implements WebMvcConfigurer {
// @Override
// public void addCorsMappings(CorsRegistry registry) {
// registry.addMapping("/**")
// .allowedOrigins("http://example.com", "http://localhost:3000")
// .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
// .allowedHeaders("Content-Type", "Authorization")
// .allowCredentials(true)
// .maxAge(3600);
// }
// }
PHP
I PHP kan du sætte CORS-headerne direkte i dit script:
<?php
header("Access-Control-Allow-Origin: http://example.com");
header("Content-Type: application/json");
$data = array("message" => "Hello from the API!");
echo json_encode($data);
?>
Sikkerhedsovervejelser ved CORS
Selvom CORS muliggør anmodninger på tværs af oprindelser, er det afgørende at forstå de sikkerhedsmæssige konsekvenser og implementere det korrekt for at undgå sårbarheder.
1. Undgå at bruge Access-Control-Allow-Origin: * i produktion
Brug af wildcard * i Access-Control-Allow-Origin-headeren tillader anmodninger fra enhver oprindelse, hvilket reelt deaktiverer same-origin policy for den pågældende ressource. Dette kan udsætte din API for ondsindede websteder, der potentielt kan stjæle brugerdata eller udføre uautoriserede handlinger. Angiv i stedet de præcise oprindelser, der har tilladelse til at tilgå ressourcen. For eksempel, hvis din webapplikation er hostet på example.com og har brug for at tilgå en API hostet på api.example.com, skal du sætte headeren til Access-Control-Allow-Origin: http://example.com.
Globalt eksempel: Forestil dig en API til en finansiel tjeneste, der sætter Access-Control-Allow-Origin: *. Et ondsindet websted kunne derefter foretage anmodninger til denne API på vegne af en logget ind bruger og potentielt overføre penge uden brugerens viden.
2. Valider Origin-headeren på serveren
Selvom du angiver en liste over tilladte oprindelser, er det vigtigt at validere Origin-headeren på serveren for at forhindre angribere i at forfalske oprindelsen. En angriber kunne potentielt sende en anmodning med en forfalsket Origin-header for at omgå CORS-kontrollerne. For at imødegå dette skal du sammenligne Origin-headeren med en liste over betroede oprindelser på server-siden. Hvis oprindelsen ikke er på listen, skal anmodningen afvises.
Globalt eksempel: Tænk på en e-handelsplatform. En angriber kunne forsøge at efterligne en legitim butiksfacades Origin for at få adgang til følsomme kundedata fra e-handelsplatformens API.
3. Vær forsigtig med Access-Control-Allow-Credentials: true
Hvis du sætter Access-Control-Allow-Credentials: true, kan Access-Control-Allow-Origin-headeren ikke sættes til *. Den skal være en specifik oprindelse. Dette skyldes, at tilladelse af legitimationsoplysninger fra enhver oprindelse kan skabe en sikkerhedsrisiko, da det kan give ondsindede websteder mulighed for at få adgang til brugerdata, hvis de kan lokke en bruger til at besøge deres side, mens brugeren også er logget ind på målsiden. Denne indstilling er vigtig, når man håndterer cookies eller authorization-headere.
Globalt eksempel: En social medieplatform, der tillader anmodninger på tværs af oprindelser med legitimationsoplysninger, kræver omhyggelig administration for at forhindre uautoriseret adgang til brugerkonti.
4. Konfigurer Access-Control-Allow-Methods og Access-Control-Allow-Headers korrekt
Tillad kun de HTTP-metoder og -headere, der er nødvendige for anmodningerne på tværs af oprindelser. Hvis du kun har brug for at tillade GET- og POST-anmodninger, skal du ikke tillade PUT, DELETE eller andre metoder. Tillad på samme måde kun de specifikke headere, som din applikation har brug for. Alt for tilladende konfigurationer kan øge risikoen for angreb.
Globalt eksempel: Et CRM-system bør kun eksponere de nødvendige API-endepunkter og -headere til autoriserede tredjepartsintegrationer for at minimere angrebsfladen.
5. Brug HTTPS til sikker kommunikation
Brug altid HTTPS til sikker kommunikation mellem browseren og serveren. HTTPS krypterer de data, der overføres mellem browseren og serveren, og forhindrer aflytning og man-in-the-middle-angreb. Brug af HTTP kan udsætte følsomme data for angribere, selvom CORS er konfigureret korrekt.
Globalt eksempel: Sundhedsapps skal bruge HTTPS for at beskytte patientdata, der overføres på tværs af forskellige oprindelser.
6. Content Security Policy (CSP)
Selvom det ikke er direkte relateret til CORS, er Content Security Policy (CSP) en anden vigtig sikkerhedsmekanisme, der kan hjælpe med at forhindre XSS-angreb. CSP giver dig mulighed for at definere en hvidliste over kilder, hvorfra browseren har tilladelse til at indlæse ressourcer. Dette kan hjælpe med at forhindre angribere i at injicere ondsindede scripts på dit websted, selvom de formår at omgå andre sikkerhedsforanstaltninger.
Globalt eksempel: Finansielle institutioner anvender ofte strenge CSP-politikker for at begrænse kilderne til indhold, der indlæses på deres netbankportaler, hvilket reducerer risikoen for XSS-angreb.
Almindelige CORS-problemer og fejlfinding
CORS-fejl kan være frustrerende at fejlfinde. Her er nogle almindelige problemer og hvordan man løser dem:
1. "No 'Access-Control-Allow-Origin' header is present on the requested resource."
Dette er den mest almindelige CORS-fejl. Den indikerer, at serveren ikke returnerer Access-Control-Allow-Origin-headeren i sit svar. Sørg for, at serveren er konfigureret til at sende de korrekte CORS-headere for oprindelsen af den webside, der foretager anmodningen. Dobbelttjek din server-side kode og konfigurationsfiler.
2. "Response to preflight request doesn't pass access control check: It does not have HTTP ok status."
Denne fejl indikerer, at preflight-anmodningen mislykkedes. Dette kan ske, hvis serveren ikke svarer på OPTIONS-anmodninger, eller hvis serveren returnerer en fejlstatuskode (f.eks. 404, 500) som svar på preflight-anmodningen. Sørg for, at din server er konfigureret til at håndtere OPTIONS-anmodninger, og at den returnerer en 200 OK-statuskode.
3. "Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'."
Denne fejl opstår, når du forsøger at sende legitimationsoplysninger (f.eks. cookies) i en anmodning på tværs af oprindelser, og Access-Control-Allow-Origin-headeren er sat til *. Som tidligere nævnt kan du ikke bruge wildcard *, når du sender legitimationsoplysninger. Du skal specificere den præcise oprindelse, der har tilladelse til at tilgå ressourcen.
4. Browser-caching
Browsere kan cache CORS-svar, hvilket kan føre til uventet adfærd, hvis CORS-konfigurationen ændres. For at forhindre cache-problemer skal du sætte Cache-Control-headeren i svaret til no-cache, no-store eller max-age=0. Du kan også bruge Access-Control-Max-Age-headeren til at kontrollere, hvor længe browseren cacher resultaterne af preflight-anmodningen.
Alternativer til CORS
Selvom CORS er standardmåden at muliggøre anmodninger på tværs af oprindelser, er der nogle alternativer, du kan overveje i visse scenarier:
1. JSON with Padding (JSONP)
JSONP er en teknik, der bruger <script>-tagget til at omgå same-origin policy. JSONP fungerer ved at pakke JSON-dataene ind i et JavaScript-funktionskald. Browseren eksekverer derefter JavaScript-funktionen og sender JSON-dataene som et argument. JSONP er enklere at implementere end CORS, men det har nogle begrænsninger. Det understøtter kun GET-anmodninger, og det er mindre sikkert end CORS.
2. Reverse Proxy
En reverse proxy er en server, der sidder foran din API-server og videresender anmodninger til den. Reverse proxyen kan konfigureres til at tilføje de nødvendige CORS-headere til svaret, hvilket effektivt skjuler anmodningerne på tværs af oprindelser for browseren. Denne tilgang kan være nyttig, hvis du ikke har kontrol over API-serveren, eller hvis du vil forenkle CORS-konfigurationen.
Konklusion
Cross-Origin Resource Sharing (CORS) er en afgørende sikkerhedsmekanisme, der tillader websider at få adgang til ressourcer fra forskellige oprindelser på en kontrolleret måde. At forstå, hvordan CORS fungerer, og at implementere det korrekt er afgørende for at bygge sikre og pålidelige webapplikationer. Ved at følge de bedste praksis, der er beskrevet i denne artikel, kan du effektivt håndtere CORS og beskytte dine API'er mod uautoriseret adgang.
Husk altid at prioritere sikkerhed, når du konfigurerer CORS. Undgå at bruge wildcards, valider Origin-headeren, og brug HTTPS til sikker kommunikation. Ved at tage disse forholdsregler kan du sikre, at dine webapplikationer er beskyttet mod cross-site-angreb.
Denne omfattende guide giver et solidt fundament for at forstå CORS. Henvis altid til den officielle dokumentation for din specifikke server-side teknologi for den mest opdaterede information og bedste praksis. Hold dig informeret om nye sikkerhedstrusler og tilpas din CORS-konfiguration i overensstemmelse hermed.